package com.maikang.exammall.entity.dto;

import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.StringUtils;

import java.util.*;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class Page {

    private Integer size;
    private Integer page;
    private List<String> sort;

    public Page(Integer size, Integer page) {
        this.size = size;
        this.page = page;
    }

    @ApiModelProperty(hidden = true)
    public Pageable getPageable() {
        if (size == null || page == null) {
            return null;
        }
        Sort sort;
        if (this.sort == null) {
            sort = Sort.unsorted();
        } else {
            sort = parseParameterIntoSort(this.sort, ",");
        }

        Pageable pageable = PageRequest.of(page, size);
        return sort.isSorted() ? PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sort) : pageable;
    }

    private Sort parseParameterIntoSort(List<String> source, String delimiter) {
        List<Sort.Order> allOrders = new ArrayList<> ();
        Iterator<String> iterator = source.iterator();
        while (true) {
            String part;
            do {
                if (!iterator.hasNext()) {
                    return allOrders.isEmpty() ? Sort.unsorted() : Sort.by(allOrders);
                }
                part = iterator.next();
            } while (part == null);
            String[] elements = Arrays.stream(part.split(delimiter)).filter(this::notOnlyDots).toArray((s) -> {
                return new String[s];
            });
            Optional<Sort.Direction> direction = elements.length == 0 ? Optional.empty() : Sort.Direction.fromOptionalString(elements[elements.length - 1]);
            int lastIndex = direction.map((it) -> {
                return elements.length-1;
            }).orElseGet(() -> {
                return elements.length;
            });
            for (int i = 0; i < lastIndex; ++i) {
                toOrder(elements[i], direction).ifPresent(allOrders::add);
            }
        }
    }

    private static Optional<Sort.Order> toOrder(String property, Optional<Sort.Direction> direction) {
        return !StringUtils.hasText(property) ? Optional.empty() : Optional.of(direction.map((it)->{
            return new Sort.Order(it, property);
        }).orElseGet(() -> {
            return Sort.Order.by(property);
        }));
    }

    private boolean notOnlyDots(String source) {
        return StringUtils.hasText(source.replace(".", ""));
    }
}
